package tcln.sors.client.main;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Date;

import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

import org.jdesktop.application.Application;
import org.jdesktop.swingx.JXDatePicker;
import org.jdesktop.swingx.JXFrame;
import org.jdesktop.swingx.JXFrame.StartPosition;
import org.jdesktop.swingx.JXMultiSplitPane;
import org.jdesktop.swingx.JXTitledPanel;
import org.jdesktop.swingx.MultiSplitLayout;
import org.jdesktop.swingx.combobox.EnumComboBoxModel;

import tcln.commons.assertion.Assert;
import tcln.commons.logging.Logger;
import tcln.sors.client.AbstractSorsView;
import tcln.sors.client.SorsApplication;
import tcln.sors.client.contact.ContactModelData;
import tcln.sors.client.contact.ProductModelData;
import tcln.sors.client.core.component.form.NamedObjectComboBox;
import tcln.sors.model.order.dom.OrderStatus;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;
import com.jgoodies.forms.layout.Sizes;

/**
 * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
 */
public class MainScreenView extends AbstractSorsView<MainScreenModelData, JXFrame> {
    private static final Logger LOGGER = Logger.getFor(MainScreenView.class);
    private static final Dimension WINDOW_SIZE = new Dimension(800, 600);
    private static final int MIN_LEFT_PANEL_WIDTH = 275;
    private static final int MIN_LEFT_PANEL_HEIGHT = 200;

    private JLabel lblProductCriterionTitle;
    private NamedObjectComboBox<ProductModelData> cbxProductCriterion;

    private JLabel lblContactCriterionTitle;
    private NamedObjectComboBox<ContactModelData> cbxContactCriterion;

    private JLabel lblExpiredDateCriterionTitle;
    private JXDatePicker dtpExpiredDateCriterion;

    private JLabel lblOrderStateCriterionTitle;
    private JComboBox cbxOrderStateCriterion;
    private JXTitledPanel pnlSearchPanel;
    private JXTitledPanel pnlSummaryPanel;

    /**
     * {@inheritDoc}
     */
    @Override
    protected JXFrame initDisplayComponent() {
        JXFrame mainFrame = initMainFrame();

        JXMultiSplitPane splitPanel = initSplitterPanel();
        mainFrame.setContentPane(splitPanel);

        initComponents(splitPanel);

        // delegate 'EXIT' action to client application
        delegateClosingHandlingToApplication(mainFrame);

        return mainFrame;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onShowing() {
        Assert.STATE.notNull(getModel(), "On showing this view, model data must not be null");

        cbxContactCriterion.setObjects(getModel().getContactModelData().getChildModels());
        cbxProductCriterion.setObjects(getModel().getProductModelData().getChildModels());

        super.onShowing();
    }

    private JXFrame initMainFrame() {
        JXFrame mainFrame = new JXFrame();

        mainFrame.setPreferredSize(WINDOW_SIZE);
        mainFrame.setSize(WINDOW_SIZE);
        mainFrame.setStartPosition(StartPosition.CenterInScreen);
        mainFrame.setResizable(true);
        mainFrame.setExtendedState(JXFrame.MAXIMIZED_BOTH);

        return mainFrame;
    }

    private Component initLeftTopComponents() {
        pnlSearchPanel = new JXTitledPanel("Search");
        pnlSearchPanel.setTitleFont(SorsApplication.getDefaultFont().bold().toJavaFont());
        pnlSearchPanel.setPreferredSize(new Dimension(MIN_LEFT_PANEL_WIDTH, MIN_LEFT_PANEL_HEIGHT));
        pnlSearchPanel.setMinimumSize(new Dimension(MIN_LEFT_PANEL_WIDTH, MIN_LEFT_PANEL_HEIGHT));
        pnlSearchPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY));

        // add search form
        initSearchForm(pnlSearchPanel);

        return pnlSearchPanel;
    }

    private void initSearchForm(JXTitledPanel container) {
        ColumnSpec[] columnSpecs = new ColumnSpec[] {

                // col 1: x-gap
                new ColumnSpec(Sizes.DLUX4),

                // col 2: label
                new ColumnSpec(ColumnSpec.LEFT, Sizes.PREFERRED, ColumnSpec.NO_GROW),

                // col 3: x-gap
                new ColumnSpec(Sizes.DLUX4),

                // col 4: field
                new ColumnSpec(ColumnSpec.FILL, Sizes.PREFERRED, ColumnSpec.DEFAULT_GROW),

                // col 5: x-gap
                new ColumnSpec(Sizes.DLUX4) };

        RowSpec[] rowSpecs = new RowSpec[] {

                // row 1: y-gap
                new RowSpec(Sizes.DLUY4),

                // row 2: order state
                new RowSpec(RowSpec.CENTER, Sizes.PREFERRED, RowSpec.NO_GROW),

                // row 3: y-gap
                new RowSpec(Sizes.DLUY4),

                // row 4: product
                new RowSpec(RowSpec.CENTER, Sizes.PREFERRED, RowSpec.NO_GROW),

                // row 5: y-gap
                new RowSpec(Sizes.DLUY4),

                // row 6: contact
                new RowSpec(RowSpec.CENTER, Sizes.PREFERRED, RowSpec.NO_GROW),

                // row 7: y-gap
                new RowSpec(Sizes.DLUY4),

                // row 8: deadline
                new RowSpec(RowSpec.CENTER, Sizes.PREFERRED, RowSpec.NO_GROW),

                // row 9: y-gap
                new RowSpec(Sizes.DLUY4) };

        FormLayout layout = new FormLayout(columnSpecs, rowSpecs);
        layout.setRowGroups(new int[][] { { 2, 4, 6, 8 } });
        JPanel formPanel = new JPanel(layout);

        CellConstraints constraints = new CellConstraints();

        lblOrderStateCriterionTitle = new JLabel("State");
        cbxOrderStateCriterion = new JComboBox(new EnumComboBoxModel<OrderStatus>(OrderStatus.class));
        formPanel.add(lblOrderStateCriterionTitle, constraints.xy(2, 2));
        formPanel.add(cbxOrderStateCriterion, constraints.xy(4, 2));

        lblProductCriterionTitle = new JLabel("Product");
        cbxProductCriterion = new NamedObjectComboBox<ProductModelData>();
        formPanel.add(lblProductCriterionTitle, constraints.xy(2, 4));
        formPanel.add(cbxProductCriterion, constraints.xy(4, 4));

        lblContactCriterionTitle = new JLabel("Contact");
        cbxContactCriterion = new NamedObjectComboBox<ContactModelData>();
        formPanel.add(lblContactCriterionTitle, constraints.xy(2, 6));
        formPanel.add(cbxContactCriterion, constraints.xy(4, 6));

        lblExpiredDateCriterionTitle = new JLabel("Deadline");
        dtpExpiredDateCriterion = new JXDatePicker(new Date());
        formPanel.add(lblExpiredDateCriterionTitle, constraints.xy(2, 8));
        formPanel.add(dtpExpiredDateCriterion, constraints.xy(4, 8));

        container.setContentContainer(formPanel);
    }

    private Component initLeftBottomComponents() {
        pnlSummaryPanel = new JXTitledPanel("Summary (TODO)");
        pnlSummaryPanel.setTitleFont(SorsApplication.getDefaultFont().bold().toJavaFont());
        pnlSummaryPanel.setPreferredSize(new Dimension(MIN_LEFT_PANEL_WIDTH, 0));
        pnlSummaryPanel.setMinimumSize(new Dimension(MIN_LEFT_PANEL_WIDTH, 0));
        pnlSummaryPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY));
        return pnlSummaryPanel;
    }

    private void initCenterComponent(JComponent container, Object constraints) {
        OrderGrid grid = new OrderGrid();

        grid.addColumn("id", "ID", 50, false);
        grid.addColumn("name", "Name", 150, false);
        grid.addColumn("creationDate", "Creation date", 50, false);
        grid.addColumn("expiryDate", "Deadline", 50, false);
        grid.addColumn("deliveryDate", "Delivered date", 50, false);
        grid.addColumn("status", "Status", 50, false);
        grid.addColumn("items.size", "No. items", 30, false);

        grid.renderTo(container, constraints);

        standardize(grid);
    }

    private void initComponents(JXMultiSplitPane splitPanel) {
        splitPanel.add(initLeftTopComponents(), "left.top");
        splitPanel.add(initLeftBottomComponents(), "left.bottom");
        initCenterComponent(splitPanel, "center");
    }

    private JXMultiSplitPane initSplitterPanel() {
        JXMultiSplitPane splitPane = new JXMultiSplitPane();

        // build layout specification
        StringBuilder layoutSpec = new StringBuilder();
        layoutSpec.append("(ROW ");
        {
            layoutSpec.append("(COLUMN (LEAF name=left.top) (LEAF name=left.bottom)) (LEAF name=center)");
        }
        layoutSpec.append(")");

        // apply to this split panel
        MultiSplitLayout.Node modelRoot = MultiSplitLayout.parseModel(layoutSpec.toString());
        splitPane.getMultiSplitLayout().setModel(modelRoot);

        return splitPane;
    }

    private void delegateClosingHandlingToApplication(JFrame frame) {
        frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                LOGGER.info("Application exit.");
                Application.getInstance().exit();
            }
        });
    }
}
